分治的思想,先分治,把数据结构不断对半分,直到最小单位,然后开始排序,再组合,递归实现。
这个题目是要把乱序的链表排成升序。由于链表的特殊结构,操作会有点复杂,不过也有比较好的方法。
- 分治 首先就是把大问题变成多个小问题,这里我们可以一直把链表对半分组。这里涉及 leetcode 876 题,找出链表的中间节点。用这个思路来把大问题化为多个小问题。
- 排列组合 第二件事就是排列组合了,把小问题排列组合成大一点的问题。这里涉及 leetcode 21 题 按顺序合并两个链表。
如此一来,一道中等难度的排序链表问题,能通过两道简单的链表查找和组合问题解决。
下面是代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
|
struct ListNode { int val; ListNode* next; ListNode() : val(0), next(nullptr) {} ListNode(int x) : val(x), next(nullptr) {} ListNode(int x, ListNode* next) : val(x), next(next) {} };
class Solution { public: ListNode* sortList(ListNode* head) { ListNode* sorted = mergeSort(head); return sorted; }
ListNode* merge(ListNode* l1, ListNode* l2) { ListNode dummy(0); ListNode* tail = &dummy; while (l1 && l2) { if (l1->val < l2->val) { tail->next = l1; l1 = l1->next; } else { tail->next = l2; l2 = l2->next; } tail = tail->next; } if (l1) { tail->next = l1; } else if (l2) { tail->next = l2; } return dummy.next; }
ListNode* mergeSort(ListNode* head) { if (!head || !head->next) { return head; } ListNode* slow = head; ListNode* fast = head->next; while (fast && fast->next) { slow = slow->next; fast = fast->next->next; } ListNode* mid = slow->next; slow->next = NULL; ListNode* left = mergeSort(head); ListNode* right = mergeSort(mid); return merge(left, right); } };
|
有个需要注意的点:
mergeSort 这个函数是用来找中点的,其中快指针是 head->next 这是为了让找到的中点为偶数中间两个的前一个,如果只是 head 的话,将会是中间的后一个。
如果是 876 题,是不能用这里的方式的,876 题求的是中间的后一个。